From 10661f3f39d8a318059dbf9f1f961fdf2e2b2912 Mon Sep 17 00:00:00 2001 From: Martin Sehnoutka Date: Fri, 23 Jun 2017 17:37:26 +0200 Subject: [PATCH] Infer multi-file binaries like `src/bin/server/main.rs` by convention --- src/cargo/util/toml.rs | 39 ++++++++++++++++++++++++++++++++++++++- tests/build.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 8450b4d4d..9cf1f5386 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -52,6 +52,7 @@ impl Layout { try_add_file(&mut bins, root_path.join("src").join("main.rs")); try_add_files(&mut bins, root_path.join("src").join("bin")); + try_add_mains_from_dirs(&mut bins, root_path.join("src").join("bin")); try_add_files(&mut examples, root_path.join("examples")); @@ -74,6 +75,26 @@ fn try_add_file(files: &mut Vec, file: PathBuf) { files.push(file); } } + +// Add directories form src/bin which contain main.rs file +fn try_add_mains_from_dirs(files: &mut Vec, root: PathBuf) { + if let Ok(new) = fs::read_dir(&root) { + let new: Vec = new.filter_map(|i| i.ok()) + // Filter only directories + .filter(|i| { + i.file_type().map(|f| f.is_dir()).unwrap_or(false) + // Convert DirEntry into PathBuf and append "main.rs" + }).map(|i| { + i.path().join("main.rs") + // Filter only directories where main.rs is present + }).filter(|f| { + f.as_path() + .exists() + }).collect(); + files.extend(new); + } +} + fn try_add_files(files: &mut Vec, root: PathBuf) { if let Ok(new) = fs::read_dir(&root) { files.extend(new.filter_map(|dir| { @@ -505,7 +526,23 @@ fn inferred_bin_targets(name: &str, layout: &Layout) -> Vec { *bin == layout.root.join("src").join("main.rs") { Some(name.to_string()) } else { - bin.file_stem().and_then(|s| s.to_str()).map(|f| f.to_string()) + // bin is either a source file or a directory with main.rs inside. + if bin.ends_with("main.rs") { + if let Some(parent) = bin.parent() { + // if the path ends with main.rs it is probably a directory, but it can also be + // a file directly inside src/bin + if parent.ends_with("src/bin") { + bin.file_stem().and_then(|s| s.to_str()).map(|f| f.to_string()) + } else { + parent.file_stem().and_then(|s| s.to_str()).map(|f| f.to_string()) + } + } else { + None + } + } else { + // regular case, just a file in the bin directory + bin.file_stem().and_then(|s| s.to_str()).map(|f| f.to_string()) + } }; name.map(|name| { diff --git a/tests/build.rs b/tests/build.rs index f2081c61f..096927a6b 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -3271,3 +3271,29 @@ fn no_bin_in_src_with_lib() { execs().with_status(101) .with_stderr_contains(r#"[ERROR] couldn't read "[..]main.rs"[..]"#)); } + + +#[test] +fn dirs_in_bin_dir_with_main_rs() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.1.0" + authors = [] + "#) + .file("src/main.rs", "fn main() {}") + .file("src/bin/bar.rs", "fn main() {}") + .file("src/bin/bar2.rs", "fn main() {}") + .file("src/bin/main.rs", "fn main() {}") + .file("src/bin/bar3/main.rs", "fn main() {}") + .file("src/bin/bar4/main.rs", "fn main() {}"); + + assert_that(p.cargo_process("build"), execs().with_status(0)); + assert_that(&p.bin("foo"), existing_file()); + assert_that(&p.bin("bar"), existing_file()); + assert_that(&p.bin("bar2"), existing_file()); + assert_that(&p.bin("bar3"), existing_file()); + assert_that(&p.bin("bar4"), existing_file()); + assert_that(&p.bin("main"), existing_file()); +} -- 2.30.2